package com.gitee.wsl.result.sample

import com.gitee.wsl.result.EntryResult
import com.gitee.wsl.result.Failure
import kotlin.jvm.JvmInline


/**
 * [ValueResult] is a type that represents either success ([Ok]) or failure ([Err]).
 *
 * A [ValueResult] that [is ok][ValueResult.isOk] will have a [value][ValueResult.value] of type [V], whereas a
 * [ValueResult] that [is an error][ValueResult.isErr] will have an [error][ValueResult.error] of type [E].
 *
 * - Elm: [Result](http://package.elm-lang.org/packages/elm-lang/core/5.1.1/Result)
 * - Haskell: [Data.Either](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Either.html)
 * - Rust: [Result](https://doc.rust-lang.org/std/result/enum.Result.html)
 */
@JvmInline
 value class ValueResult<out V, out E> internal constructor(
    private val inlineValue: Any?,
) : EntryResult<V, E> {

    @Suppress("UNCHECKED_CAST")
    override val value: V
        get() = inlineValue as V

    @Suppress("UNCHECKED_CAST")
    override val error: E
        get() = (inlineValue as Failure<E>).error

    override val isOk: Boolean
        get() = inlineValue !is Failure<*>

    override val isErr: Boolean
        get() = inlineValue is Failure<*>

    override operator fun component1(): V? {
        return when {
            isOk -> value
            else -> null
        }
    }

    override operator fun component2(): E? {
        return when {
            isErr -> error
            else -> null
        }
    }

    override fun toString(): String {
        return when {
            isOk -> "Ok($value)"
            else -> "Err($error)"
        }
    }

    companion object{
        /**
         * Returns a [ValueResult] that [is ok][ValueResult.isOk] and contains a [value][ValueResult.value].
         */
        @Suppress("FunctionName")
         fun <V> Ok(value: V): ValueResult<V, Nothing> {
            return ValueResult(value)
        }

        /**
         * Returns a [ValueResult] that [is an error][ValueResult.isErr] and contains an [error][ValueResult.error].
         */
        @Suppress("FunctionName")
         fun <E> Err(error: E): ValueResult<Nothing, E> {
            return ValueResult(Failure(error))
        }
    }
}


